#!/usr/bin/env python
#coding:utf-8

import tornado
from ..baseHandler import BaseHandler
from bson import ObjectId
from ..error import ErrorHandler
import uuid
import datetime


class UserHandler(BaseHandler):

    #本处理器用来处理用户相关信息接口
    # @tornado.web.asynchronous
    @tornado.gen.coroutine
    def get(self,*args, **kwargs):
        #检测获取用户的信息的类别
        userId = ''
        if len(args):
            try:
                userId = ObjectId(args[0])
            except Exception:
                return ErrorHandler.write_error(self,status_code=202,message='objectId处理出错')
        #若有传递用户ID则返回用户个人信息
        if userId:
            res = yield self.db.user.find_once({'_id':userId})
        else:
            res = yield self.db.user.find().limit(100).to_list(100)
        return self.response_msg(200,'ok',res)



    #2.注册接口(tornado中的url参数会直接放入args中)
    @tornado.gen.coroutine
    def post(self):
        #注册逻辑
        (arguments,error) = yield self.get_select_argument(['mobile','password'],['Oauth_type','Oauth_data'])
        if not arguments:
            return ErrorHandler.write_error(self,status_code=102,message=error)
        #验证手机号码和密码强度
        if self.phone_check(arguments['mobile']):
            if self.pass_check(arguments['password']):
                #对密码进行加密加盐
                salt = get_user_token()
                arguments['password'] = self.md5(arguments['password'] + salt)
                #写入个人不同的盐
                arguments['token'] = salt
                #首先生产user的session_token,产生的算法
                baseCode = uuid.uuid1()
                #产生的uuid再做一次MD5加密
                lastCode = self.md5(str(baseCode))
                arguments['session_token'] = lastCode
                #注册之前先检测数据库中是否存在
                (status,info) = yield LoginHandler.check_user(self,arguments['mobile'])
                if status != 0:
                    return ErrorHandler.write_error(self,status_code=106,message="该手机号已经注册，请直接登陆")
                #如果使用的是第三方登陆注册则需要添加对应的第三方登陆信息
                if 'Oauth_type' in arguments:
                    if 'Oauth_data' not in arguments:
                        del arguments['Oauth_type']
                        return ErrorHandler.write_error(self,status_code=107,message="第三方注册请提供认证信息")
                    else:
                        #检查该第三方账号是否已经被使用
                        (Oauth_exsits_check_status,info) = yield self.Oauth_exsists_check(arguments['Oauth_type'],arguments['Oauth_data'])
                        if Oauth_exsits_check_status:
                            return ErrorHandler.write_error(self,status_code=108,message="该第三方账号已经绑定过本系统其他账号，请重新登陆")
                        else:
                            arguments['socail_login'] = {}
                            arguments['socail_login']['Oauth_type'] = arguments['Oauth_type']
                            arguments['socail_login']['Oauth_data'] = arguments['Oauth_data']
                            del arguments['Oauth_type']
                            del arguments['Oauth_data']
                else:
                    if 'Oauth_data' in arguments:
                        del arguments['Oauth_data']

                #注册用户，写入数据库
                res = yield self.db.user.insert(arguments)
                if res:
                    arguments['objectId'] = str(res)
                    del arguments['_id']
                    #注册用户的同时需要给用户添加积分信息，且积分添加成功与否不影响注册流程
                    self.sign_add_points(arguments['objectId'])
                    return self.response_msg(200,'注册成功',self.find_formart(arguments))
                else:
                    return ErrorHandler.write_error(self,status_code=103,message='注册失败')
            else:
                return ErrorHandler.write_error(self,status_code=105,message='密码不符合要求')
        else:
            return ErrorHandler.write_error(self,status_code=104,message='手机号码非法')

    #修改用户基本信息接口
    def put(self):
        pass

    def delete(self):
        pass

    def head(self, *args, **kwargs):
        pass

    def options(self):
        pass

    def patch(self):
        pass

    @tornado.gen.coroutine
    def Oauth_exsists_check(self,login_type,data):
        #验证第三方账号信息是否已经被注册
        res = yield self.db.user.find_one({'socail_login.Oauth_type':login_type,'socail_login.Oauth_data':data})
        if res:
            return (True,res)
        else:
            return (False,res)


    def sign_add_points(self,userId,number):
        try:
            #首先向积分记录中添加记录
            points_add = yield self.db.points.insert({  "user" : userId,
                                                        "old_points" : "0",
                                                        "operation" : "sign",
                                                        "number" : self.config['SIGN_POINTS_NUMBER'],
                                                        "operate_target" : userId,
                                                        "operate_locate" : "user",
                                                        "created_at" : datetime.datetime.now()
                                                        })
            if points_add:
                user_points_add = yield self.db.user_points.update({
                                                        "user" : userId,
                                                        "total" : self.config['SIGN_POINTS_NUMBER']
                                                        })
                if user_points_add:
                    pass
                else:
                    #插入失败则清除掉前面的积分项
                    self.db.points.remove({'_id':ObjectId(points_add)})
        except Exception as e:
            self.db.logs.insert({"user":userId,"op":"sign","reson":"注册添加积分失败","error":str(e)})
        return True

#
# 登陆逻辑
#
class LoginHandler(BaseHandler):
    #处理登陆逻辑
    @tornado.gen.coroutine
    def post(self, *args, **kwargs):
        #对参数进行获取
        (arguments,e) = yield self.get_select_argument(['login_type'],['mobile','password','Oauth_type','Oauth_data'])
        if not arguments:
            return ErrorHandler.write_error(self,status_code=201,message=e)
        #判断登陆类型,normal,socail
        if arguments['login_type'] == 'normal':
            if 'mobile' in arguments and 'password' in arguments:
                #对登陆信息进行检查，得出登陆状态1表示通过，0表示用户不存在，1表示用户密码错误
                (status,info) = yield self.check_user(arguments['mobile'],arguments['password'])
                if status == 1:
                    #检查通过则，更新user的session_token
                    userInfo = yield self.login_done(info['_id'])
                    if userInfo is not None:
                        info['session_token'] = userInfo
                        del info['_id']
                        return self.response_msg(200,'登陆成功',self.find_formart(info))
                    else:
                        return self.response_msg(202,'更新状态失败')
                elif status == 0:
                    return self.response_msg(203,'用户名不存在')
                else:
                    return self.response_msg(204,'密码错误')
            else:
                return ErrorHandler.write_error(self,status_code=205,message="账号密码不能为空")
        else:
            if 'Oauth_type' in arguments and 'Oauth_data' in arguments:
                (status,info) = yield UserHandler.Oauth_exsists_check(self,arguments['Oauth_type'],arguments['Oauth_data'])
                if status is True:
                    del info['_id']
                    return self.response_msg(200,'登陆成功',self.find_formart(info))
                else:
                    #这个逻辑交由前台跳入输入手机号码界面，完成第三方登陆地注册
                    return ErrorHandler.write_error(self,status_code=206,message="该第三方账号未绑定")



    #检查用户的登陆状态
    @tornado.gen.coroutine
    def check_user(self,username,password=''):
        #根据用户名获取用户信息
        userInfo = yield self.db.user.find_one({'$or':[{'username':username},{'mobile':username}]})
        #获取用户加盐密码
        if userInfo is not None:
            if password:
                local_pass = self.md5(password + userInfo['token'])
                if userInfo['password'] == local_pass:
                    return (1,userInfo)
                else:
                    return (-1,None)
            else:
                return (1,None)
        else:
            return (0,None)


    #完成用户登陆功能，写入用户session_token,标记登陆状态
    @tornado.gen.coroutine
    def login_done(self,id):
        #首先生产user的session_token,产生的算法
        baseCode = uuid.uuid1()
        #产生的uuid再做一次MD5加密
        lastCode = self.md5(str(baseCode))
        #将生产的session_token写入数据库
        res = yield self.db.user.update({'_id':id},{'$set':{'session_token':lastCode}})
        if res['updatedExisting']:
            return lastCode
        else:
            return None


class LoginOutHandler(BaseHandler):
    #处理登出逻辑
    @tornado.gen.coroutine
    def post(self, *args, **kwargs):
        self._check_op_access()
        if self.access == False:
            return ErrorHandler.write_error(self,status_code=303,message='验证不通过，请检查登陆状态')
        #获取参数
        (arguments,error) = yield self.get_select_argument(['objectId'])
        if not arguments:
            return ErrorHandler.write_error(self,status_code=304,message=error)
        #退出登陆状态需要将session_token制空
        res = yield self.db.user.update({'_id':ObjectId(arguments['objectId'])},{'$set':{'session_token':''}})
        if res['updatedExisting']:
            return self.response_msg(200,'退出成功')
        else:
            return ErrorHandler.write_error(self,status_code=305,message='退出失败，请稍后再试')



class PassWordHandler(BaseHandler):
    #修改用户密码接口
    @tornado.gen.coroutine
    def post(self, *args, **kwargs):
        self._check_op_access()
        if self.access == False:
            return ErrorHandler.write_error(self,status_code=303,message='验证不通过，请检查登陆状态')
        #获取参数
        (arguments,error) = yield self.get_select_argument(['objectId','new_password'])
        if not arguments:
            return ErrorHandler.write_error(self,status_code=304,message=error)
        #检查用户新密码
        if self.pass_check(arguments['new_password']):
            #对密码加盐处理
            salt = get_user_token()
            new_password = self.md5(arguments['new_password'] + salt)
            res = yield self.db.user.update({'_id':ObjectId(arguments['objectId'])},{'$set':{'password':new_password,'token':salt,'session_token':''}})
            if res['updatedExisting']:
                return self.response_msg(200,'修改密码成功')
            else:
                return ErrorHandler.write_error(self,status_code=305,message='修改密码失败，请稍后再试')
        else:
            return ErrorHandler.write_error(self,status_code=306,message='密码不符合要求')





#生产随机字符串用做密码加盐
def get_user_token():
    from random import choice
    return ''.join([choice('AaBbCcDdEeFfGgHhIiJjKkLlMmNnOoPpQqRrSsTtUuVvWwXxYyZz0123456789') for i in range(8)])



handlers = [(r"/user", UserHandler),
            (r"/user/(.*)", UserHandler),
            (r"/login",LoginHandler),
            (r"/loginout",LoginOutHandler),
            (r"/password",PassWordHandler),
            ]